package cn.com.nes.site.service.crm.opportunity.impl;

import cn.com.nes.common.em.DictTypeEnum;
import cn.com.nes.common.exception.IllegalBusinessException;
import cn.com.nes.common.exception.MissBusinessParameterException;
import cn.com.nes.common.util.XzqhUtils;
import cn.com.nes.mybatis.agent.crm.entity.Opportunity;
import cn.com.nes.mybatis.agent.crm.entity.OpportunityDeviceModel;
import cn.com.nes.mybatis.agent.crm.mapper.OpportunityMapper;
import cn.com.nes.mybatis.agent.system.entity.SystemXzqh;
import cn.com.nes.site.controller.crm.opportunity.vo.ExportTemplateExcelOfEndCustomerVO;
import cn.com.nes.site.entity.em.DeleteEnum;
import cn.com.nes.site.entity.em.crm.log.LogOperateTypeEnum;
import cn.com.nes.site.entity.em.crm.opportunity.OpportunityStageEnum;
import cn.com.nes.site.entity.em.crm.opportunity.RenovationType;
import cn.com.nes.site.entity.iot.CascadeCell;
import cn.com.nes.site.entity.iot.NameCascade;
import cn.com.nes.site.service.crm.customer.bo.CustomerOpportunityBo;
import cn.com.nes.site.service.crm.log.LogOperateService;
import cn.com.nes.site.service.crm.log.bo.LogOperateBO;
import cn.com.nes.site.service.crm.opportunity.CrmOpportunityService;
import cn.com.nes.site.service.crm.opportunity.OpportunityAreaCodeService;
import cn.com.nes.site.service.crm.opportunity.OpportunityDeviceModelService;
import cn.com.nes.site.service.crm.opportunity.bo.GetOpportunityDetailBO;
import cn.com.nes.site.service.crm.opportunity.bo.OpportunityBO;
import cn.com.nes.site.service.crm.opportunity.bo.QueryOpportunityBO;
import cn.com.nes.site.service.crm.opportunity.bo.QueryOpportunityPageBO;
import cn.com.nes.site.service.crm.opportunity.dto.OpportunityAndContractDTO;
import cn.com.nes.site.service.crm.opportunity.dto.OpportunityAreaCodeDTO;
import cn.com.nes.site.service.crm.opportunity.dto.OpportunityDTO;
import cn.com.nes.site.service.crm.opportunity.dto.OpportunityInfoDto;
import cn.com.nes.site.service.system.dict.TParamService;
import cn.com.nes.site.service.system.region.XzqhService;
import cn.com.nes.site.service.system.region.dto.XzqhDTO;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class CrmOpportunityServiceImpl extends ServiceImpl<OpportunityMapper, Opportunity> implements CrmOpportunityService {

    private static final int MAX_ROW = 5000;    // 每页下拉框最大行数

    private static final int MAX_YEAR = 50;     // 距今最大年限

    @Resource
    private XzqhService xzqhService;

    @Resource
    private TParamService tParamService;

    @Resource
    private LogOperateService logOperateService;

    @Resource
    private OpportunityAreaCodeService opportunityAreaCodeService;

    @Resource
    private OpportunityDeviceModelService opportunityDeviceModelService;

    /**
     * 处理商机阶段
     * @param opportunityUuid
     * @param opportunityStageEnum
     * @param operateUserId
     * @param operateDate
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleOpportunityStage(String opportunityUuid, OpportunityStageEnum opportunityStageEnum,
            Long operateUserId, Date operateDate, String operateCompanyId, String operateUserName) throws Exception {
        if (StrUtil.isEmpty(opportunityUuid) || ObjectUtil.isNull(opportunityStageEnum) || ObjectUtil.isNull(operateUserId) || ObjectUtil.isNull(operateDate)) {
            throw new MissBusinessParameterException("业务参数不合法");
        }

        Opportunity opportunity = this.getOpportunity(opportunityUuid);

        switch (opportunityStageEnum) {
            case _follow_up:
                if (!opportunity.getOpportunityStage().equals(OpportunityStageEnum._new.getKey())) {
                    return;
                }
                log.debug("商务项目阶段修改为跟进中");
                break;
            case _loss:
                if (!opportunity.getOpportunityStage().equals(OpportunityStageEnum._follow_up.getKey())) {
                    return;
                }
                log.debug("商务项目阶段修改为失败");
                break;
            case _transaction:
                if (!opportunity.getOpportunityStage().equals(OpportunityStageEnum._follow_up.getKey())) {
                    return;
                }
                log.debug("商务项目阶段修改为成交");
                break;
            default:
                break;
        }

        changeOpportunityStage(opportunity, opportunityStageEnum, operateUserId, operateDate);
        this.updateById(opportunity);

        // 记录操作日志
        LogOperateBO logOperateBO = new LogOperateBO();
        logOperateBO.setOpportunityUuid(opportunityUuid);
        logOperateBO.setLogType(LogOperateTypeEnum.OPPORTUNITY);
        logOperateBO.setOperateTime(operateDate);
        logOperateBO.setOperateUserId(operateUserId);
        logOperateBO.setRemark("变更商机阶段为：" + opportunityStageEnum.getValue());
        logOperateService.saveLogOperate(logOperateBO);
    }

    /**
     * 改变商务项目阶段
     * @param opportunity
     * @param opportunityStageEnum
     * @param operateUserId
     * @param operateDate
     */
    private void changeOpportunityStage(Opportunity opportunity, OpportunityStageEnum opportunityStageEnum,
            Long operateUserId, Date operateDate) throws Exception {
        opportunity.setOpportunityStage(opportunityStageEnum.getKey());
        opportunity.setModifyUid(String.valueOf(operateUserId));
        opportunity.setModifyTime(operateDate);
    }


    @Override
    public Opportunity getOpportunity(String opportunityUUid) {
        if (StrUtil.isNotEmpty(opportunityUUid)) {
            Opportunity opportunity = this.baseMapper.selectById(opportunityUUid);
            return ObjectUtil.isNull(opportunity) ? new Opportunity() : opportunity;
        }
        return new Opportunity();
    }

    @Override
    public List<Opportunity> getOpportunities(QueryOpportunityBO queryOpportunityBo) throws Exception {
        QueryWrapper<Opportunity> opportunityWrapper = new QueryWrapper<Opportunity>().eq("isdelete", Boolean.FALSE);
        if (StrUtil.isNotEmpty(queryOpportunityBo.getCustomerUuid())) {
            opportunityWrapper.eq("customerId", queryOpportunityBo.getCustomerUuid());
        }
        if (StrUtil.isNotEmpty(queryOpportunityBo.getOpportunityUuid())) {
            opportunityWrapper.eq("uuid", queryOpportunityBo.getOpportunityUuid());
        }
        return this.baseMapper.selectList(opportunityWrapper);
    }

    @Override
    public List<OpportunityAndContractDTO> getOpportunitiesContainContract(
            QueryOpportunityBO queryOpportunityBo) throws Exception {
        return this.baseMapper.getOpportunitiesContainContract(queryOpportunityBo);
    }

    @Override
    public List<OpportunityDTO> getCustomerOpportunityList(CustomerOpportunityBo customerOpportunityBo) {
        return this.baseMapper.getCustomerOpportunityList(customerOpportunityBo);
    }

    /**
     * 根据商机id查询商机的详情
     * 这个接口直接返回了Opportunity的对象，没使用DTO包装，是因为外面嵌套了PageData类，自动转换为Object类型，没有必要多余地转换一次
     * @param uuid
     * @return
     */
    @Override
    public Opportunity getOpportunityDetailByUuid(String uuid) throws Exception {
        Opportunity opportunity = this.baseMapper.selectById(uuid);
        if (ObjectUtil.isNull(opportunity)) {
            throw new IllegalBusinessException("获取商机信息失败!");
        }
        return opportunity;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteByCustomerIds(List<String> deletedCustomerIds, Long operateUserId,
            Date operateDate) throws Exception {
        if (CollUtil.isEmpty(deletedCustomerIds)) {
            throw new MissBusinessParameterException("请传入要删除的客户ID");
        }
        this.baseMapper.deleteByCustomerIds(deletedCustomerIds, operateUserId, operateDate);
    }

    @Override
    public Opportunity getOpportunity(String customerUuid, String opportunityUuid) {
        QueryWrapper<Opportunity> wrapper = new QueryWrapper<>();
        wrapper.eq("isdelete", DeleteEnum._0.getKey());
        wrapper.eq("customerId", customerUuid);
        wrapper.eq("uuid", opportunityUuid);
        return this.getOne(wrapper);
    }

    /**
     * 商机成交
     * @param opportunityBO
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void opportunitySuccess(OpportunityBO opportunityBO) throws Exception {
        if (StrUtil.isEmpty(opportunityBO.getUuid())) {
            throw new IllegalBusinessException("商机ID");
        }
        handleOpportunityStage(opportunityBO.getUuid(), opportunityBO.getOpportunityStage(), opportunityBO.getOperateUserId(), opportunityBO.getOperateDate(), opportunityBO.getOperateUserName(), opportunityBO.getOperateUserCompanyId());
    }

    /**
     * 商机列表分页查询
     * @param bo
     * @return
     */
    @Override
    public Page<OpportunityInfoDto> getOpportunityPage(QueryOpportunityPageBO bo) throws Exception {
        Page<OpportunityInfoDto> page = new Page<>(bo.getPageid(), bo.getPagesize());
        // 分页查询商机信息
        List<OpportunityInfoDto> opportunityPageList = this.baseMapper.getOpportunityPage(page, bo);
        page.setRecords(opportunityPageList);
        return page;
    }

    @Override
    public OpportunityInfoDto getOpportunityBaseInfo(GetOpportunityDetailBO bo) throws Exception {
        return this.baseMapper.getOpportunityInfoDto(bo);
    }

    @Override
    public List<CascadeCell> getEndCustomerSaleTemplateExcelHeaderCellContent(
            ExportTemplateExcelOfEndCustomerVO vo) throws Exception {
        List<CascadeCell> cascadeCellList = new ArrayList<>();
        cascadeCellList.add(getAreaNameConfig(vo));         // 行政区划
        cascadeCellList.add(getBuildingStructureConfig());  // 建筑结构
        cascadeCellList.add(getHouseTypeConfig());          // 房屋类型
        cascadeCellList.add(getHeatingEndConfig());         // 采暖末端
        cascadeCellList.add(getRenovationtyoeConfig());      // 改造类型
        cascadeCellList.add(getPlayYearConfig());           // 计划年度
        cascadeCellList.add(getEnergyTypeConfig());         // 能源类型
        cascadeCellList.add(getHeatingTypeNameConfig());    // 供暖方式
        cascadeCellList.add(getEquipmentModelConfig(vo.getOpportunityUuid()));   // 设备型号
        cascadeCellList.add(getTrueOrFalseConfig());        // 是否本村户籍
        return cascadeCellList;
    }

    @Override
    public List<List<String>> getEndCustomerSaleTemplateExcelHeaders(String opportunityUuid) throws Exception {
        Opportunity opportunity = getOpportunity(opportunityUuid);
        String headerNameStr_1 = opportunity.getOpportunityName() + "-" + opportunity.getPlanYear() + "年度-终端客户表";
        String headerNameStr_2 = "说明：标题有*的，为必填项";
        String headerNameStr_3 = "行政区划*,地址*,门牌号,户主姓名*,身份证号码*,电话号码*,建筑面积,建筑结构,房屋类型,采暖末端,计划年度,改造类型,能源类型,电表号/燃气表号,供暖方式,设备型号,是否本村户籍,备注";

        List<List<String>> header = new ArrayList<>();
        String[] headerNameList = headerNameStr_3.split(",");
        for (String headerName : headerNameList) {
            header.add(Arrays.asList(headerNameStr_1, headerNameStr_2, headerName));
        }
        return header;
    }

    @Override
    public Opportunity getOpportunityByName(String customerUuid, String opportunityName) throws Exception {
        QueryWrapper<Opportunity> wrapper = new QueryWrapper<>();
        wrapper.eq("isdelete", DeleteEnum._0.getKey());
        wrapper.eq("opportunityname", opportunityName);
        wrapper.eq("customerId", customerUuid);
        return this.getOne(wrapper);
    }

    @Override
    public List<String> getCoverageArea(String opportunityUuid) throws Exception {
        if (StrUtil.isEmpty(opportunityUuid)) {
            throw new MissBusinessParameterException("opportunityUuid must not be empty");
        }
        List<OpportunityAreaCodeDTO> areaCodes = opportunityAreaCodeService.getAreaCodesByOpportunityUuid(opportunityUuid);
        if (CollectionUtil.isEmpty(areaCodes)) {
            return Collections.emptyList();
        }

        // 获取当前权限的行政区划
        List<String> setAreaCodes = areaCodes.stream()
                .map(OpportunityAreaCodeDTO::getXzqhdm)
                .distinct()
                .collect(Collectors.toList());
        List<SystemXzqh> systemXzqhs = (List<SystemXzqh>) xzqhService.listByIds(setAreaCodes);

        // 1、只有上级代码，获取所有子行政区划
        // 2、有上级及部分下级代码，获取下级的所有行政区划代码
        for (SystemXzqh systemXzqh : systemXzqhs) {
            // 获取当前行政区划代码级别
            String regionCodePrefix = XzqhUtils.getRegionCodePrefix(systemXzqh.getXzqhdm());
            boolean match = systemXzqhs.stream()
                    .filter(xzqh -> !xzqh.getXzqhdm().equals(systemXzqh.getXzqhdm()))
                    .anyMatch(xzqh -> xzqh.getXzqhdm()
                            .startsWith(regionCodePrefix));
            if (match) {
                log.info("符合匹配 - {}", systemXzqh.getXzqhdm());
            } else {
                List<SystemXzqh> areacodes = xzqhService.getListByPrefix(regionCodePrefix);
                if (CollUtil.isNotEmpty(areacodes)) {
                    setAreaCodes.addAll(areacodes.stream().map(SystemXzqh::getXzqhdm).filter(xzqh -> !xzqh.equals(systemXzqh.getXzqhdm())).collect(Collectors.toList()));
                }
            }
        }
        return setAreaCodes.stream().distinct().collect(Collectors.toList());
    }

    @Override
    public List<String> getSettingDeviceModels(String opportunityUuid) throws Exception {
        if (StrUtil.isEmpty(opportunityUuid)) {
            throw new MissBusinessParameterException("opportunityUuid must not be empty");
        }

        List<OpportunityDeviceModel> deviceModels = opportunityDeviceModelService.getDeviceModels(opportunityUuid);
        if (CollectionUtil.isEmpty(deviceModels)) {
            return Collections.emptyList();
        }

        return deviceModels.stream().map(OpportunityDeviceModel::getDeviceModel).collect(Collectors.toList());
    }

    @Override
    public OpportunityInfoDto getOpportunityDetailByWorkOrderId(Long workOrderId) {
        OpportunityInfoDto opportunityInfoDto = this.baseMapper.getOpportunityDetailByWorkOrderId(workOrderId);
        if (ObjectUtil.isNotNull(opportunityInfoDto)) {
            opportunityInfoDto.setRenovationTypeName(RenovationType.enumConvertKeyToValue(opportunityInfoDto.getRenovationType()));
        }
        return opportunityInfoDto;
    }

    // 获取导出模板行政区划名称下拉框列表
    private CascadeCell getAreaNameConfig(ExportTemplateExcelOfEndCustomerVO vo) throws Exception {
        List<XzqhDTO> xzqhDTOList = xzqhService.getXzqhListByXzqhdmList(vo.getXzqhdmList());
        if (CollectionUtil.isEmpty(xzqhDTOList)) {
            throw new Exception("行政区划为空,模板下载失败!");
        }
        List<NameCascade> nameCascadeList = new ArrayList<>();
        getChildList(xzqhDTOList, nameCascadeList);

        CascadeCell cascadeCell = new CascadeCell();
        cascadeCell.setRowIndex(3);
        cascadeCell.setColumnIndex(0);
        cascadeCell.setRowNum(MAX_ROW);
        cascadeCell.setNameCascadeList(nameCascadeList.stream().distinct().collect(Collectors.toList()));
        return cascadeCell;
    }

    // 获取行政区划编码名称
    private void getChildList(List<XzqhDTO> xzqhDTOList, List<NameCascade> nameCascadeList) {
        for (XzqhDTO item : xzqhDTOList) {
            if (!"5".equals(item.getXzqhjb())) {
                getXzqhName(item.getChildList(), nameCascadeList);
            } else {
                NameCascade nameCascade = new NameCascade();
                nameCascade.setName(item.getXzqhdm() + "_" + item.getXzqhmc());
                /*  nameCascade.setName(item.getXzqhmc());*/
                nameCascadeList.add(nameCascade);
            }
        }
    }

    private void getXzqhName(List<XzqhDTO> xzqhDTOList, List<NameCascade> nameCascadeList) {
        for (XzqhDTO item : xzqhDTOList) {
            NameCascade nameCascade = new NameCascade();
            nameCascade.setName(item.getXzqhdm() + "_" + item.getXzqhmc());
            /* nameCascade.setName(item.getXzqhmc());*/
            nameCascadeList.add(nameCascade);
        }
    }

    // 建筑结构
    private CascadeCell getBuildingStructureConfig() throws Exception {
        List<Map<String, String>> configTemplate = tParamService.getListMap(DictTypeEnum.BUILDING_STRUCTURE.getParamType());
        return assembleConfig(configTemplate, 7);
    }

    // 房屋类型
    private CascadeCell getHouseTypeConfig() throws Exception {
        List<Map<String, String>> configTemplate = tParamService.getListMap(DictTypeEnum.HOUSE_TYPE.getParamType());
        return assembleConfig(configTemplate, 8);
    }

    // 采暖末端
    private CascadeCell getHeatingEndConfig() throws Exception {
        List<Map<String, String>> configTemplate = tParamService.getListMap(DictTypeEnum.HEATING_END.getParamType());
        return assembleConfig(configTemplate, 9);
    }

    // 计划年度
    private CascadeCell getPlayYearConfig() {
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);

        List<NameCascade> nameCascadeList = new ArrayList<>();
        for (int i = 0; i < MAX_YEAR; i++) {
            NameCascade nameCascade = new NameCascade();
            nameCascade.setName((year + i) + "");
            nameCascadeList.add(nameCascade);
        }

        CascadeCell cascadeCell = new CascadeCell();
        cascadeCell.setRowIndex(3);
        cascadeCell.setColumnIndex(10);
        cascadeCell.setRowNum(MAX_ROW);
        cascadeCell.setNameCascadeList(nameCascadeList);
        return cascadeCell;
    }

    // 改造类型
    private CascadeCell getRenovationtyoeConfig() throws Exception {
        List<Map<String, String>> configTemplate = tParamService.getListMap(DictTypeEnum.RENOVATION_TYPE.getParamType());
        return assembleConfig(configTemplate, 11);
    }

    // 能源类型
    private CascadeCell getEnergyTypeConfig() throws Exception {
        List<Map<String, String>> configTemplate = tParamService.getListMap(DictTypeEnum.ENERGY_TYPE.getParamType());
        return assembleConfig(configTemplate, 12);
    }

    // 供暖方式
    private CascadeCell getHeatingTypeNameConfig() throws Exception {
        List<Map<String, String>> configTemplate = tParamService.getListMap(DictTypeEnum.HEATING_MODE.getParamType());
        return assembleConfig(configTemplate, 14);
    }

    private CascadeCell getEquipmentModelConfig(String opportunityUuid) throws Exception {
        List<OpportunityDeviceModel> deviceModels = opportunityDeviceModelService.getDeviceModels(opportunityUuid);
        // 组装选项
        List<NameCascade> nameCascadeList = new ArrayList<>();
        for (OpportunityDeviceModel deviceModel : deviceModels) {
            NameCascade nameCascade = new NameCascade();
            /* nameCascade.setName(item.get("name"));*/
            nameCascade.setName(deviceModel.getDeviceModel() + "[" + deviceModel.getDeviceModelName() + "]");
            nameCascadeList.add(nameCascade);
        }
        // 组装配置
        CascadeCell cascadeCell = new CascadeCell();
        cascadeCell.setRowIndex(3);
        cascadeCell.setColumnIndex(15);
        cascadeCell.setRowNum(MAX_ROW);
        cascadeCell.setNameCascadeList(nameCascadeList);
        return cascadeCell;
    }

    // 是否本村户籍
    private CascadeCell getTrueOrFalseConfig() {
        // 配置选项
        Map<String, String> map_1 = new HashMap<>();
        map_1.put("value", "0");
        map_1.put("name", "否");

        Map<String, String> map_2 = new HashMap<>();
        map_2.put("value", "1");
        map_2.put("name", "是");

        List<Map<String, String>> configTemplate = new ArrayList<>();
        configTemplate.add(map_1);
        configTemplate.add(map_2);
        return assembleConfig(configTemplate, 16);
    }

    // 组装配置
    private CascadeCell assembleConfig(List<Map<String, String>> configTemplate, Integer columnIndex) {
        // 组装选项
        List<NameCascade> nameCascadeList = new ArrayList<>();
        for (Map<String, String> item : configTemplate) {
            NameCascade nameCascade = new NameCascade();
            /* nameCascade.setName(item.get("name"));*/
            nameCascade.setName(item.get("value") + "_" + item.get("name"));
            nameCascadeList.add(nameCascade);
        }
        // 组装配置
        CascadeCell cascadeCell = new CascadeCell();
        cascadeCell.setRowIndex(3);
        cascadeCell.setColumnIndex(columnIndex);
        cascadeCell.setRowNum(MAX_ROW);
        cascadeCell.setNameCascadeList(nameCascadeList);
        return cascadeCell;
    }

}
